/**
 * @file config.cpp
 * @brief ConfigWeave 核心实现：View/Builder 与内部工具。
 */
#include "config.h"

#include <algorithm>
#include <cctype>
#include <cmath>
#include <limits>
#ifdef CFG_ENABLE_YAML
#include <yaml-cpp/yaml.h>
#endif
#include <regex>

namespace cfg
{

/**
 * @brief 在对象中根据键查找属性值。
 * @param obj 目标对象
 * @param key 键名
 * @return 指向值的指针，若不存在返回 nullptr。
 */
static const Value *
get_prop(const Object & obj, std::string_view key)
{
    auto it = obj.props.find(std::string(key));
    if (it == obj.props.end())
        return nullptr;
    return &it->second;
}

/**
 * @brief 将数组 Value 转换为只读 span 视图。
 * @param v 值
 * @return 成功返回只读数组视图；否则返回 TypeMismatch 错误。
 */
static expected<span<const Value>, ConfigError>
value_as_array_view(const Value & v)
{
    if (auto parr = std::get_if<std::shared_ptr<const Array>>(&v))
    {
        if (!*parr)
        {
            return span<const Value>{};
        }
        const auto & items = (*parr)->items;
        return span<const Value>(items.data(), items.size());
    }
    return unexpected(ConfigError{Errc::TypeMismatch, "not an array", {}});
}

#ifdef CFG_ENABLE_YAML
/**
 * @brief 递归将 YAML::Node 转换为 cfg::Value。
 * @param node YAML 节点
 * @param normalize_keys_fn 键规整函数；若为空则使用恒等函数
 * @return 转换后的不可变 Value。
 */
static Value
yaml_node_to_value(const YAML::Node & node,
                   const std::function<std::string(std::string_view)> & normalize_keys_fn)
{
    if (node.IsNull())
    {
        return nullptr;
    }

    if (node.IsScalar())
    {
        // 尝试按 bool -> int64_t -> double -> string 的顺序解析
        try
        {
            bool b = node.as<bool>();
            return b;
        }
        catch (const YAML::BadConversion &)
        {
        }

        try
        {
            long long ll = node.as<long long>();
            return static_cast<int64_t>(ll);
        }
        catch (const YAML::BadConversion &)
        {
        }

        try
        {
            double d = node.as<double>();
            return d;
        }
        catch (const YAML::BadConversion &)
        {
        }

        return node.as<std::string>();
    }

    if (node.IsSequence())
    {
        auto mut_arr = std::make_shared<Array>();
        mut_arr->items.reserve(node.size());
        for (const auto & item : node)
        {
            mut_arr->items.emplace_back(yaml_node_to_value(item, normalize_keys_fn));
        }
        std::shared_ptr<const Array> carr = mut_arr;
        return carr;
    }

    if (node.IsMap())
    {
        auto mut_obj = std::make_shared<Object>();
        for (const auto & kv : node)
        {
            std::string key = kv.first.as<std::string>();
            // 应用键规整
            std::string norm_key = normalize_keys_fn ? normalize_keys_fn(key) : key;
            mut_obj->props.emplace(std::move(norm_key),
                                   yaml_node_to_value(kv.second, normalize_keys_fn));
        }
        std::shared_ptr<const Object> cobj = mut_obj;
        return cobj;
    }

    // 未知节点类型，按 null 处理
    return nullptr;
}
#endif

/// ---------------- View 实现 ----------------

/// 构造根视图：将根 Object 包装为 Value 的 Object 指针形式，确保 _current 有效。
View::View(std::shared_ptr<const Object> root) noexcept : _root(std::move(root)), _current(nullptr)
{
    if (_root)
    {
        _owned_value = std::make_unique<Value>(std::shared_ptr<const Object>(_root));
        _current = _owned_value.get();
    }
}

/// 拷贝构造：深拷贝 _owned_value；若 other._current 指向其
/// _owned_value，则重定向到当前副本；否则共享底层树中的节点指针。
View::View(const View & other) : _root(other._root), _current(nullptr), _path(other._path)
{
    if (other._owned_value)
    {
        _owned_value = std::make_unique<Value>(*other._owned_value);
        _current =
            (other._current == other._owned_value.get()) ? _owned_value.get() : other._current;
    }
    else
    {
        _current = other._current; // 指向同一底层只读树中的节点
    }
}

/// 移动构造：转移所有权并保持 _current 指向的节点位置。
View::View(View && other) noexcept
    : _root(std::move(other._root)),
      _current(other._current),
      _owned_value(std::move(other._owned_value)),
      _path(std::move(other._path))
{
    other._current = nullptr;
}

/// 拷贝赋值：语义同拷贝构造。
View &
View::operator=(const View & other)
{
    if (this == &other)
        return *this;
    _root = other._root;
    _path = other._path;

    if (other._owned_value)
    {
        _owned_value = std::make_unique<Value>(*other._owned_value);
        _current =
            (other._current == other._owned_value.get()) ? _owned_value.get() : other._current;
    }
    else
    {
        _owned_value.reset();
        _current = other._current;
    }
    return *this;
}

/// 移动赋值：语义同移动构造。
View &
View::operator=(View && other) noexcept
{
    if (this == &other)
        return *this;
    _root = std::move(other._root);
    _current = other._current;
    _owned_value = std::move(other._owned_value);
    _path = std::move(other._path);
    other._current = nullptr;
    return *this;
}

/// 逐段下钻对象属性。
expected<View, ConfigError>
View::subobj(std::string_view key) const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});

    const Value & v = *_current;
    if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&v))
    {
        const Value * child = (*pobj) ? get_prop(**pobj, key) : nullptr;
        if (!child)
        {
            auto pth = _path;
            pth.emplace_back(std::string(key));
            return unexpected(ConfigError{Errc::MissingKey, "key not found", std::move(pth)});
        }
        View next(*this);
        next._current = child;
        next._path.emplace_back(std::string(key));
        return next;
    }
    return unexpected(ConfigError{Errc::TypeMismatch, "not an object", _path});
}

/// 数组按索引访问。
expected<View, ConfigError>
View::at(size_t index) const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});

    const Value & v = *_current;
    if (auto parr = std::get_if<std::shared_ptr<const Array>>(&v))
    {
        if (!*parr || index >= (*parr)->items.size())
        {
            auto pth = _path;
#if CFG_HAVE_STD_FORMAT
            pth.emplace_back(std::format("[{}]", index));
#else
            pth.emplace_back("[" + std::to_string(index) + "]");
#endif
            return unexpected(ConfigError{Errc::OutOfRange, "index out of range", std::move(pth)});
        }
        View next(*this);
        next._current = &(*parr)->items[index];
#if CFG_HAVE_STD_FORMAT
        next._path.emplace_back(std::format("[{}]", index));
#else
        next._path.emplace_back("[" + std::to_string(index) + "]");
#endif
        return next;
    }
    return unexpected(ConfigError{Errc::TypeMismatch, "not an array", _path});
}

/// 判断当前对象是否包含给定键。
bool
View::has(std::string_view key) const noexcept
{
    if (_current == nullptr)
        return false;
    const Value & v = *_current;
    if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&v))
    {
        if (!*pobj)
            return false;
        return (*pobj)->props.find(std::string(key)) != (*pobj)->props.end();
    }
    return false;
}

/// 路径解析：支持 a.b[2].c 语法（不支持转义与引号）。
expected<View, ConfigError>
View::lookup(std::string_view path) const
{
    /// JSON Pointer 风格解析（RFC 6901 子集）：以 '/' 开头，段由 '/' 分隔；
    /// 解码规则："~1" -> '/', "~0" -> '~'；若段末尾出现悬空的 '~'，按字面含义处理（兼容写入用例）。
    /// 语义：
    ///  - 对象节点：段作为键名查找；
    ///  - 数组节点：段需为非负整数作为索引；
    ///  - 其他类型：若仍有剩余段则返回 TypeMismatch。
    if (path.empty())
    {
        return *this;
    }
    if (!path.empty() && path[0] == '/')
    {
        auto decode_segment = [](std::string_view seg) -> expected<std::string, ConfigError>
        {
            std::string out;
            out.reserve(seg.size());
            for (size_t i = 0; i < seg.size(); ++i)
            {
                char c = seg[i];
                if (c == '~')
                {
                    if (i + 1 >= seg.size())
                    {
                        // 兼容：段尾悬空 '~' 视为字面 '~'
                        out.push_back('~');
                        continue;
                    }
                    char n = seg[i + 1];
                    if (n == '0')
                    {
                        out.push_back('~');
                        ++i;
                    }
                    else if (n == '1')
                    {
                        out.push_back('/');
                        ++i;
                    }
                    else
                    {
                        return unexpected(ConfigError{
                            Errc::InvalidPath,
                            "invalid escape in JSON pointer: '~' must be followed by '0' or '1'",
                            {}});
                    }
                }
                else
                {
                    out.push_back(c);
                }
            }
            return out;
        };

        View cur = *this;
        size_t pos = 1; // 跳过首个 '/'
        while (true)
        {
            size_t next = path.find('/', pos);
            std::string_view raw_seg =
                (next == std::string::npos) ? path.substr(pos) : path.substr(pos, next - pos);
            auto key_decoded = decode_segment(raw_seg).transform_error(
                [&](const ConfigError & e) {
                    return ConfigError{e.code, e.message, cur.path()};
                });
            if (!key_decoded)
                return unexpected(key_decoded.error());
            const Value * cur_val = cur._current;
            if (cur_val == nullptr)
            {
                return unexpected(ConfigError{Errc::Other, "invalid view state", cur.path()});
            }

            if (auto pobj = std::get_if<std::shared_ptr<const Object>>(cur_val))
            {
                auto r = cur.subobj(*key_decoded)
                             .transform_error(
                                 [&](const ConfigError & e) {
                                     return ConfigError{e.code, e.message, cur.path()};
                                 });
                if (!r)
                    return r;
                cur = *r;
            }
            else if (auto parr = std::get_if<std::shared_ptr<const Array>>(cur_val))
            {
                const std::string & seg = *key_decoded;
                if (seg.empty() || !std::all_of(seg.begin(),
                                                seg.end(),
                                                [](unsigned char ch) { return std::isdigit(ch); }))
                {
                    return unexpected(ConfigError{
                        Errc::InvalidPath, "invalid array index in JSON pointer", cur.path()});
                }
                size_t idx = 0;
                for (char ch : seg)
                {
                    idx = idx * 10 + static_cast<size_t>(ch - '0');
                }
                auto r = cur.at(idx).transform_error(
                    [&](const ConfigError & e) {
                        return ConfigError{e.code, e.message, cur.path()};
                    });
                if (!r)
                    return r;
                cur = *r;
            }
            else
            {
                return unexpected(
                    ConfigError{Errc::TypeMismatch, "not an object or array", cur.path()});
            }

            if (next == std::string::npos)
                return cur; // 结束
            pos = next + 1; // 跳过 '/'
        }
    }

    // 回退到传统路径解析：支持 a.b[2].c 语法（不支持转义与引号）
    View cur = *this;
    size_t i = 0, n = path.size();
    while (i < n)
    {
        if (path[i] == '.')
        {
            ++i;
            continue;
        }

        std::string key;
        while (i < n && path[i] != '.' && path[i] != '[')
        {
            key.push_back(path[i]);
            ++i;
        }
        if (!key.empty())
        {
            auto r = cur.subobj(key).transform_error(
                [&](const ConfigError & e) {
                    return ConfigError{e.code, e.message, cur.path()};
                });
            if (!r)
                return r;
            cur = *r;
        }

        while (i < n && path[i] == '[')
        {
            ++i; // skip '['
            if (i >= n || !std::isdigit(static_cast<unsigned char>(path[i])))
                return unexpected(
                    ConfigError{Errc::InvalidPath, "invalid array index", cur.path()});
            size_t idx = 0;
            while (i < n && std::isdigit(static_cast<unsigned char>(path[i])))
            {
                idx = idx * 10 + static_cast<size_t>(path[i] - '0');
                ++i;
            }
            if (i >= n || path[i] != ']')
                return unexpected(
                    ConfigError{Errc::InvalidPath, "missing closing ']'", cur.path()});
            auto r = cur.at(idx).transform_error(
                [&](const ConfigError & e) {
                    return ConfigError{e.code, e.message, cur.path()};
                });
            if (!r)
                return r;
            cur = *r;
            ++i; // skip ']'
        }

        if (i < n && path[i] == '.')
            ++i;
    }
    return cur;
}

expected<span<const Value>, ConfigError>
View::array_view() const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});
    const Value & v = *_current;
    return value_as_array_view(v).transform_error(
        [&](const ConfigError & e) {
            return ConfigError{e.code, e.message, _path};
        });
}

expected<const Object *, ConfigError>
View::object_view() const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});

    const Value & v = *_current;
    if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&v))
    {
        return pobj->get();
    }
    return unexpected(ConfigError{Errc::TypeMismatch, "not an object", _path});
}

expected<int64_t, ConfigError>
View::get_int64() const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});
    const Value & v = *_current;
    if (auto pi = std::get_if<int64_t>(&v))
        return *pi;
    if (auto pd = std::get_if<double>(&v))
    {
        /// 要求 double 为整数且在 int64_t 范围内。
        double d = *pd;
        if (std::isfinite(d) && std::floor(d) == d &&
            d >= static_cast<double>(std::numeric_limits<int64_t>::min()) &&
            d <= static_cast<double>(std::numeric_limits<int64_t>::max()))
        {
            return static_cast<int64_t>(d);
        }
        return unexpected(ConfigError{Errc::TypeMismatch, "cannot convert number to int64", _path});
    }
    return unexpected(ConfigError{Errc::TypeMismatch, "not an integer", _path});
}

expected<double, ConfigError>
View::get_number() const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});
    const Value & v = *_current;
    if (auto pd = std::get_if<double>(&v))
        return *pd;
    if (auto pi = std::get_if<int64_t>(&v))
        return static_cast<double>(*pi);
    return unexpected(ConfigError{Errc::TypeMismatch, "not a number", _path});
}

expected<std::string, ConfigError>
View::get_string() const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});
    const Value & v = *_current;
    if (auto ps = std::get_if<std::string>(&v))
        return *ps;
    return unexpected(ConfigError{Errc::TypeMismatch, "not a string", _path});
}

expected<bool, ConfigError>
View::get_bool() const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});
    const Value & v = *_current;
    if (auto pb = std::get_if<bool>(&v))
        return *pb;
    return unexpected(ConfigError{Errc::TypeMismatch, "not a bool", _path});
}

/// 判断当前视图节点是否为 null。
/// 返回 true 表示底层 Value 为 std::nullptr_t；若视图无效则返回 false。
bool
View::is_null() const
{
    if (_current == nullptr)
        return false;
    return std::holds_alternative<std::nullptr_t>(*_current);
}

std::optional<SchemaValueType>
View::value_type() const
{
    if (_current == nullptr)
        return std::nullopt;
    const Value & v = *_current;
    if (std::holds_alternative<std::nullptr_t>(v))
        return SchemaValueType::Null;
    if (std::holds_alternative<bool>(v))
        return SchemaValueType::Bool;
    if (std::holds_alternative<int64_t>(v))
        return SchemaValueType::Int64;
    if (std::holds_alternative<double>(v))
        return SchemaValueType::Number;
    if (std::holds_alternative<std::string>(v))
        return SchemaValueType::String;
    if (std::holds_alternative<std::shared_ptr<const Array>>(v))
        return SchemaValueType::Array;
    if (std::holds_alternative<std::shared_ptr<const Object>>(v))
        return SchemaValueType::Object;
    return std::nullopt;
}
expected<std::vector<View::Entry>, ConfigError>
View::entries() const
{
    if (_current == nullptr)
        return unexpected(ConfigError{Errc::Other, "invalid view state", _path});
    const Value & v = *_current;
    if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&v))
    {
        if (*pobj)
        {
            std::vector<Entry> out;
            out.reserve((*pobj)->props.size());
            for (const auto & kv : (*pobj)->props)
            {
                out.push_back(Entry{std::string_view(kv.first), kv.second});
            }
            return out;
        }
        return std::vector<Entry>{};
    }
    return unexpected(ConfigError{Errc::TypeMismatch, "not an object", _path});
}

const std::vector<std::string> &
View::path() const noexcept
{
    return _path;
}

/// 传统路径写入：支持 "a.b[2].c" 语法，自动扩容数组与创建中间对象。
/// 语义：
///  - 用 '.' 分段键名；每个键名后可接若干个数组下标如 "key[0][1]"；
///  - 中间节点自动创建：遇到下一个键段前，若当前位置为元素槽位，则转换为对象；
///  - 数组下标必须为非负整数；路径起始不得以 '[' 开头；
///  - 任何解析错误会记录 Errc::InvalidPath，并保持已有树不变（最佳努力）。
/**
 * @brief 使用点分路径与数组下标写入配置值
 * @param path 路径字符串，如 `a.b[0][1]`，点分键名可附带多个数组下标
 * @param v 要写入的值
 * @return 返回 `Builder&`，支持链式调用
 * @details
 * - 路径不能为空且不得以 `'['` 开头；
 * - 中间节点按需创建：遇到下一个键段前，若当前位置为元素槽位则转换为对象；
 * - 数组下标必须为非负整数；解析错误记录 `Errc::InvalidPath` 并保留已有树不变。
 */
Builder &
Builder::set(std::string path, Value v)
{
    if (path.empty())
    {
        _errors.push_back(ConfigError{Errc::InvalidPath, "empty path", {}});
        return *this;
    }
    if (path[0] == '[')
    {
        _errors.push_back(ConfigError{Errc::InvalidPath, "missing key before index", {}});
        return *this;
    }

    Object * cur_obj = &_root_object;
    Value * cur_slot = nullptr; // 指向当前键或数组元素的槽位

    size_t i = 0;
    const size_t n = path.size();

    auto ensure_object_at_slot = [&](Value * slot) -> Object *
    {
        if (!std::holds_alternative<std::shared_ptr<const Object>>(*slot))
        {
            auto mut = std::make_shared<Object>();
            *slot = std::shared_ptr<const Object>(mut);
            return mut.get();
        }
        auto pobj = std::get<std::shared_ptr<const Object>>(*slot);
        if (pobj)
            return const_cast<Object *>(pobj.get());
        auto mut = std::make_shared<Object>();
        *slot = std::shared_ptr<const Object>(mut);
        return mut.get();
    };

    auto ensure_array_at_slot = [&](Value * slot) -> std::shared_ptr<Array>
    {
        if (auto parr = std::get_if<std::shared_ptr<const Array>>(slot))
        {
            if (*parr)
                return std::make_shared<Array>(**parr);
            return std::make_shared<Array>();
        }
        return std::make_shared<Array>();
    };

    while (i < n)
    {
        // 解析键段（直到 '.' 或 '[' 或末尾）
        const size_t key_start = i;
        while (i < n && path[i] != '.' && path[i] != '[')
            ++i;
        if (i == key_start)
        {
            _errors.push_back(ConfigError{Errc::InvalidPath, "empty key segment", {}});
            return *this;
        }
        std::string key = path.substr(key_start, i - key_start);
        if (_normalize)
            key = _normalize(key);

        // 若来自上一轮留下的元素槽位，需要先把它变为对象并进入
        if (cur_slot != nullptr)
        {
            cur_obj = ensure_object_at_slot(cur_slot);
            cur_slot = nullptr;
        }

        // 获取到对象属性槽位
        cur_slot = &cur_obj->props[key];

        // 紧随其后可能有若干 [index]
        while (i < n && path[i] == '[')
        {
            ++i; // 跳过 '['
            if (i >= n)
            {
                _errors.push_back(ConfigError{Errc::InvalidPath, "missing ']' for index", {}});
                return *this;
            }
            size_t idx = 0;
            bool has_digit = false;
            while (i < n && std::isdigit(static_cast<unsigned char>(path[i])))
            {
                has_digit = true;
                idx = idx * 10 + static_cast<size_t>(path[i] - '0');
                ++i;
            }
            if (!has_digit || i >= n || path[i] != ']')
            {
                _errors.push_back(ConfigError{Errc::InvalidPath, "invalid array index", {}});
                return *this;
            }
            ++i; // 跳过 ']'

            // 确保当前槽位为数组并扩容
            auto mut_arr = ensure_array_at_slot(cur_slot);
            *cur_slot = std::shared_ptr<const Array>(mut_arr);
            if (idx >= mut_arr->items.size())
                mut_arr->items.resize(idx + 1);
            cur_slot = &mut_arr->items[idx];
        }

        if (i >= n)
        {
            // 末段，直接写入
            *cur_slot = std::move(v);
            return *this;
        }
        if (path[i] == '.')
        {
            ++i; // 跳过 '.'，交由下一轮将元素槽位提升为对象
            if (i >= n)
            {
                _errors.push_back(ConfigError{Errc::InvalidPath, "trailing '.' in path", {}});
                return *this;
            }
            continue;
        }

        // 非法字符（括号处理已覆盖）
        _errors.push_back(ConfigError{Errc::InvalidPath, "unexpected character in path", {}});
        return *this;
    }

    return *this;
}

/**
 * @brief 以 JSON Pointer（RFC 6901 子集）写入值
 * @param path 指针路径，以 `'/'` 起始；支持空键段与 `~0`/`~1` 转义
 * @param v 要写入的值
 * @return 返回 `Builder&`，支持链式调用
 * @details
 * - 支持空键名段（`"//"` 表示空字符串键）；
 * - 支持 `~0`→`~`、`~1`→`/` 的转义；其他以 `~` 开头的转义视为非法；
 * - 自动扩容数组索引并按需创建对象容器；对象写入时应用键名规范化（若已配置）。
 */
Builder &
Builder::set_pointer(std::string path, Value v)
{
    // 作用：按 JSON Pointer 语法（RFC 6901 子集）将值写入构建树。
    // 特性：
    //  - 支持空键名段（"//" 表示空字符串键）。
    //  - 支持 "~0"→"~"、"~1"→"/" 的转义解码；若段末尾为悬空 '~'，按字面含义处理（兼容写入用例）。
    //  - 其他以 '~' 开头且不为上述两种的转义视为非法。
    //  - 支持对数组索引的自动扩容与对象容器的按需创建。
    //  - 键名在写入对象时应用 _normalize（若已配置）。

    if (path.empty() || path[0] != '/')
    {
        _errors.push_back(ConfigError{Errc::InvalidPath, "JSON pointer must start with '/'", {}});
        return *this;
    }

    auto decode_segment = [](std::string_view seg) -> expected<std::string, ConfigError>
    {
        std::string out;
        out.reserve(seg.size());
        for (size_t i = 0; i < seg.size(); ++i)
        {
            char c = seg[i];
            if (c == '~')
            {
                if (i + 1 >= seg.size())
                {
                    // 兼容：段尾悬空 '~' 视为字面 '~'
                    out.push_back('~');
                    continue;
                }
                char n = seg[i + 1];
                if (n == '0')
                {
                    out.push_back('~');
                    ++i;
                }
                else if (n == '1')
                {
                    out.push_back('/');
                    ++i;
                }
                else
                {
                    return unexpected(ConfigError{
                        Errc::InvalidPath,
                        "invalid escape in JSON pointer: '~' must be followed by '0' or '1'",
                        {}});
                }
            }
            else
            {
                out.push_back(c);
            }
        }
        return out;
    };

    Object * cur_obj = &_root_object;
    Value * cur_slot = nullptr; // 若非空，表示下一段可能是索引，应以此为基进行数组化

    size_t pos = 1; // 跳过首个 '/'
    while (true)
    {
        size_t next = path.find('/', pos);
        std::string_view raw_seg = (next == std::string::npos)
                                       ? std::string_view(path).substr(pos)
                                       : std::string_view(path).substr(pos, next - pos);
        auto seg_decoded = decode_segment(raw_seg);
        if (!seg_decoded)
        {
            _errors.push_back(ConfigError{Errc::InvalidPath, "invalid escape in JSON pointer", {}});
            return *this;
        }
        const std::string & seg = *seg_decoded; // 允许为空（空键名）

        bool is_last = (next == std::string::npos);
        bool is_index =
            (!seg.empty() && std::all_of(seg.begin(),
                                         seg.end(),
                                         [](unsigned char ch) { return std::isdigit(ch); }));

        if (is_index)
        {
            // 必须已有“基槽位”（来自上一段的对象键或数组元素）
            if (cur_slot == nullptr)
            {
                _errors.push_back(
                    ConfigError{Errc::InvalidPath, "array index without base value", {}});
                return *this;
            }

            // 确保基槽位为数组
            std::shared_ptr<Array> mut_arr;
            if (auto parr = std::get_if<std::shared_ptr<const Array>>(cur_slot))
            {
                if (*parr)
                    mut_arr = std::make_shared<Array>(**parr);
                else
                    mut_arr = std::make_shared<Array>();
            }
            else
            {
                mut_arr = std::make_shared<Array>();
            }
            *cur_slot = std::shared_ptr<const Array>(mut_arr);

            // 解析索引并扩容
            size_t idx = 0;
            for (char ch : seg)
                idx = idx * 10 + static_cast<size_t>(ch - '0');
            if (idx >= mut_arr->items.size())
                mut_arr->items.resize(idx + 1);

            if (is_last)
            {
                mut_arr->items[idx] = std::move(v);
                return *this;
            }
            else
            {
                // 前瞻下一段，决定是否将该元素提升为对象
                size_t pos2 = next + 1;
                size_t next2 = path.find('/', pos2);
                std::string_view raw_next = (next2 == std::string::npos)
                                                ? std::string_view(path).substr(pos2)
                                                : std::string_view(path).substr(pos2, next2 - pos2);
                auto next_decoded = decode_segment(raw_next);
                if (!next_decoded)
                {
                    _errors.push_back(
                        ConfigError{Errc::InvalidPath, "invalid escape in JSON pointer", {}});
                    return *this;
                }
                const std::string & next_seg = *next_decoded;
                bool next_is_index = (!next_seg.empty() && std::all_of(next_seg.begin(),
                                                                       next_seg.end(),
                                                                       [](unsigned char ch) {
                                                                           return std::isdigit(ch);
                                                                       }));

                if (next_is_index)
                {
                    // 保留数组元素槽位，交由下一段再次作为数组处理
                    cur_slot = &mut_arr->items[idx];
                }
                else
                {
                    // 下一段为键：将当前位置转为对象并进入
                    if (!std::holds_alternative<std::shared_ptr<const Object>>(mut_arr->items[idx]))
                    {
                        auto mut_obj = std::make_shared<Object>();
                        mut_arr->items[idx] = std::shared_ptr<const Object>(mut_obj);
                        cur_obj = mut_obj.get();
                    }
                    else
                    {
                        auto pobj = std::get<std::shared_ptr<const Object>>(mut_arr->items[idx]);
                        if (pobj)
                            cur_obj = const_cast<Object *>(pobj.get());
                        else
                        {
                            auto mut_obj = std::make_shared<Object>();
                            mut_arr->items[idx] = std::shared_ptr<const Object>(mut_obj);
                            cur_obj = mut_obj.get();
                        }
                    }
                    cur_slot = nullptr; // 进入对象键解析
                }
            }
        }
        else
        {
            // 键段：若携带了上一段遗留的槽位，需将其提升为对象并“进入”
            if (cur_slot != nullptr)
            {
                if (!std::holds_alternative<std::shared_ptr<const Object>>(*cur_slot))
                {
                    auto mut_obj = std::make_shared<Object>();
                    *cur_slot = std::shared_ptr<const Object>(mut_obj);
                    cur_obj = mut_obj.get();
                }
                else
                {
                    auto pobj = std::get<std::shared_ptr<const Object>>(*cur_slot);
                    if (pobj)
                        cur_obj = const_cast<Object *>(pobj.get());
                    else
                    {
                        auto mut_obj = std::make_shared<Object>();
                        *cur_slot = std::shared_ptr<const Object>(mut_obj);
                        cur_obj = mut_obj.get();
                    }
                }
                cur_slot = nullptr;
            }

            // 写入或定位键槽位（支持空键名）
            const std::string key = (_normalize ? _normalize(seg) : seg);
            cur_slot = &cur_obj->props[key];

            if (is_last)
            {
                *cur_slot = std::move(v);
                return *this;
            }
            // 非最后一段：延迟容器创建，下一轮根据段类型决定转成对象或数组
        }

        if (next == std::string::npos)
            break;
        pos = next + 1;
    }

    return *this;
}

/**
 * @brief 判断两个 `Value` 是否相等（用于数组去重）
 * @param a 左值
 * @param b 右值
 * @return 相等返回 `true`，否则返回 `false`
 * @details
 * - 标量类型（`nullptr_t`、`bool`、`int64_t`、`double`、`std::string`）按值比较；
 * - 数组与对象仅在共享指针地址相等时视为相等（不做结构化深比较）。
 */
static bool
values_equal(const Value & a, const Value & b)
{
    if (a.index() != b.index())
        return false;

    if (std::holds_alternative<std::nullptr_t>(a))
        return true;
    if (auto pa = std::get_if<bool>(&a))
        return *pa == std::get<bool>(b);
    if (auto pa = std::get_if<int64_t>(&a))
        return *pa == std::get<int64_t>(b);
    if (auto pa = std::get_if<double>(&a))
        return *pa == std::get<double>(b);
    if (auto pa = std::get_if<std::string>(&a))
        return *pa == std::get<std::string>(b);
    if (auto pa = std::get_if<std::shared_ptr<const Array>>(&a))
    {
        auto pb = std::get<std::shared_ptr<const Array>>(b);
        return pa->get() == pb.get();
    }
    if (auto pa = std::get_if<std::shared_ptr<const Object>>(&a))
    {
        auto pb = std::get<std::shared_ptr<const Object>>(b);
        return pa->get() == pb.get();
    }
    return false;
}

// 合并对象：浅合并（后写覆盖先写）或深合并（递归），冲突遵循 _conflict_policy
// 函数语义：
// - 当 _merge_strategy 为 Shallow 时：
//     - 对于 src.props 中的每个键 k：
//         - 若目标无该键，则直接插入；
//         - 若目标已有该键，则按照 _conflict_policy=Overwrite/Keep/Error 处理；
// - 当 _merge_strategy 为 Deep 时：
//     - 若同名键双方均为对象，则递归合并；
/**
 * @brief 将对象内容合并到构建树根对象
 * @param obj 待合并的对象
 * @return 返回 `Builder&`，支持链式调用
 * @details
 * - 浅合并：同键覆盖标量；数组按去重追加；对象按键覆盖；
 * - 深合并：对象递归合并；类型不兼容视为冲突，按 `ConflictPolicy` 处理；
 * - `Error` 策略将冲突记录到 `_errors`（不抛异常）；`PreferNew` 则以新值覆盖。
 */
Builder &
Builder::merge_object(const Object & obj)
{
    if (_merge_strategy == MergeStrategy::Shallow)
    {
        for (const auto & kv : obj.props)
        {
            auto it = _root_object.props.find(kv.first);
            if (it == _root_object.props.end())
            {
                _root_object.props.emplace(kv.first, kv.second);
            }
            else
            {
                switch (_conflict_policy)
                {
                    case ConflictPolicy::Overwrite:
                        it->second = kv.second;
                        break;
                    case ConflictPolicy::Keep:
                        // 保留已有，忽略新值
                        break;
                    case ConflictPolicy::Error:
                        _errors.push_back(
                            ConfigError{Errc::Other,
                                        std::string("merge conflict on key '") + kv.first + "'",
                                        {kv.first}});
                        break;
                }
            }
        }
    }
    else // Deep 合并
    {
        for (const auto & kv : obj.props)
        {
            auto it = _root_object.props.find(kv.first);
            if (it == _root_object.props.end())
            {
                _root_object.props.emplace(kv.first, kv.second);
                continue;
            }

            // 顶层：两侧若为对象则递归合并；若为数组则按数组策略合并；否则按冲突策略
            if (std::holds_alternative<std::shared_ptr<const Object>>(it->second) &&
                std::holds_alternative<std::shared_ptr<const Object>>(kv.second))
            {
                auto lhs_ptr = std::get<std::shared_ptr<const Object>>(it->second);
                auto rhs_ptr = std::get<std::shared_ptr<const Object>>(kv.second);
                auto lhs_mut = std::make_shared<Object>(lhs_ptr ? *lhs_ptr : Object{});
                if (rhs_ptr)
                {
                    for (const auto & rr : rhs_ptr->props)
                    {
                        auto li = lhs_mut->props.find(rr.first);
                        if (li == lhs_mut->props.end())
                        {
                            lhs_mut->props.emplace(rr.first, rr.second);
                        }
                        else
                        {
                            // 冲突处理（对象-对象 / 数组-数组 / 其他）
                            if (std::holds_alternative<std::shared_ptr<const Object>>(li->second) &&
                                std::holds_alternative<std::shared_ptr<const Object>>(rr.second))
                            {
                                // 递归：对象-对象
                                auto lsub = std::get<std::shared_ptr<const Object>>(li->second);
                                auto rsub = std::get<std::shared_ptr<const Object>>(rr.second);
                                auto lmut = std::make_shared<Object>(lsub ? *lsub : Object{});
                                if (rsub)
                                {
                                    for (const auto & r2 : rsub->props)
                                        lmut->props[r2.first] = r2.second;
                                }
                                li->second = std::shared_ptr<const Object>(lmut);
                            }
                            else if (std::holds_alternative<std::shared_ptr<const Array>>(
                                         li->second) &&
                                     std::holds_alternative<std::shared_ptr<const Array>>(
                                         rr.second))
                            {
                                // 数组合并，依据 _array_merge_strategy
                                auto la = std::get<std::shared_ptr<const Array>>(li->second);
                                auto ra = std::get<std::shared_ptr<const Array>>(rr.second);
                                auto out = std::make_shared<Array>();
                                if (_array_merge_strategy == ArrayMergeStrategy::Overwrite)
                                {
                                    if (ra)
                                        *out = *ra;
                                }
                                else if (_array_merge_strategy == ArrayMergeStrategy::Append)
                                {
                                    if (la)
                                        out->items = la->items;
                                    if (ra)
                                        out->items.insert(
                                            out->items.end(), ra->items.begin(), ra->items.end());
                                }
                                else if (_array_merge_strategy == ArrayMergeStrategy::Deduplicate)
                                {
                                    if (la)
                                        out->items = la->items;
                                    if (ra)
                                    {
                                        for (const auto & vv : ra->items)
                                        {
                                            bool dup = false;
                                            for (const auto & exist : out->items)
                                            {
                                                if (values_equal(vv, exist))
                                                {
                                                    dup = true;
                                                    break;
                                                }
                                            }
                                            if (!dup)
                                                out->items.push_back(vv);
                                        }
                                    }
                                }
                                else if (_array_merge_strategy == ArrayMergeStrategy::Keyed)
                                {
                                    // 仅对对象数组生效，按照 _array_merge_key 进行合并；否则退化为
                                    // Append
                                    std::unordered_map<std::string, size_t> index;
                                    if (la)
                                    {
                                        for (size_t i = 0; i < la->items.size(); ++i)
                                        {
                                            const Value & iv = la->items[i];
                                            if (auto pobj =
                                                    std::get_if<std::shared_ptr<const Object>>(&iv))
                                            {
                                                if (*pobj)
                                                {
                                                    const Value * keyv =
                                                        get_prop(**pobj, _array_merge_key);
                                                    if (keyv)
                                                    {
                                                        if (auto ks =
                                                                std::get_if<std::string>(keyv))
                                                            index[*ks] = i;
                                                        else if (auto ki =
                                                                     std::get_if<int64_t>(keyv))
                                                            index[std::to_string(*ki)] = i;
                                                    }
                                                }
                                            }
                                        }
                                        out->items = la->items;
                                    }
                                    if (ra)
                                    {
                                        for (const auto & iv : ra->items)
                                        {
                                            if (auto pobj =
                                                    std::get_if<std::shared_ptr<const Object>>(&iv))
                                            {
                                                if (*pobj)
                                                {
                                                    const Value * keyv =
                                                        get_prop(**pobj, _array_merge_key);
                                                    std::string key;
                                                    if (keyv)
                                                    {
                                                        if (auto ks =
                                                                std::get_if<std::string>(keyv))
                                                            key = *ks;
                                                        else if (auto ki =
                                                                     std::get_if<int64_t>(keyv))
#if CFG_HAVE_STD_FORMAT
                                                            key = std::format("{}", *ki);
#else
                                                            key = std::to_string(*ki);
#endif
                                                    }
                                                    if (!key.empty())
                                                    {
                                                        auto it2 = index.find(key);
                                                        if (it2 != index.end())
                                                        {
                                                            out->items[it2->second] =
                                                                iv; // 覆盖更新
                                                        }
                                                        else
                                                        {
                                                            out->items.push_back(iv);
                                                            index[key] = out->items.size() - 1;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        out->items.push_back(iv); // 缺键：直接追加
                                                    }
                                                }
                                                else
                                                {
                                                    out->items.push_back(iv);
                                                }
                                            }
                                            else
                                            {
                                                out->items.push_back(iv);
                                            }
                                        }
                                    }
                                }
                                li->second = std::shared_ptr<const Array>(out);
                            }
                            else
                            {
                                // 非容器或不同类型，按冲突策略
                                switch (_conflict_policy)
                                {
                                    case ConflictPolicy::Overwrite:
                                        li->second = rr.second;
                                        break;
                                    case ConflictPolicy::Keep:
                                        break;
                                    case ConflictPolicy::Error:
                                        _errors.push_back(ConfigError{
                                            Errc::Other,
                                            std::string("merge conflict on key '") + rr.first + "'",
                                            {rr.first}});
                                        break;
                                }
                            }
                        }
                    }
                }
                it->second = std::shared_ptr<const Object>(lhs_mut);
            }
            else if (std::holds_alternative<std::shared_ptr<const Array>>(it->second) &&
                     std::holds_alternative<std::shared_ptr<const Array>>(kv.second))
            {
                // 顶层：数组-数组合并
                auto la = std::get<std::shared_ptr<const Array>>(it->second);
                auto ra = std::get<std::shared_ptr<const Array>>(kv.second);
                auto out = std::make_shared<Array>();
                if (_array_merge_strategy == ArrayMergeStrategy::Overwrite)
                {
                    if (ra)
                        *out = *ra;
                }
                else if (_array_merge_strategy == ArrayMergeStrategy::Append)
                {
                    if (la)
                        out->items = la->items;
                    if (ra)
                        out->items.insert(out->items.end(), ra->items.begin(), ra->items.end());
                }
                else if (_array_merge_strategy == ArrayMergeStrategy::Deduplicate)
                {
                    if (la)
                        out->items = la->items;
                    if (ra)
                    {
                        for (const auto & vv : ra->items)
                        {
                            bool dup = false;
                            for (const auto & exist : out->items)
                            {
                                if (values_equal(vv, exist))
                                {
                                    dup = true;
                                    break;
                                }
                            }
                            if (!dup)
                                out->items.push_back(vv);
                        }
                    }
                }
                else if (_array_merge_strategy == ArrayMergeStrategy::Keyed)
                {
                    // 仅对对象数组生效，按照 _array_merge_key 进行合并；否则退化为 Append
                    std::unordered_map<std::string, size_t> index;
                    if (la)
                    {
                        for (size_t i = 0; i < la->items.size(); ++i)
                        {
                            const Value & iv = la->items[i];
                            if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&iv))
                            {
                                if (*pobj)
                                {
                                    const Value * keyv = get_prop(**pobj, _array_merge_key);
                                    if (keyv)
                                    {
                                        if (auto ks = std::get_if<std::string>(keyv))
                                            index[*ks] = i;
                                        else if (auto ki = std::get_if<int64_t>(keyv))
                                            index[std::to_string(*ki)] = i;
                                    }
                                }
                            }
                        }
                        out->items = la->items;
                    }
                    if (ra)
                    {
                        for (const auto & iv : ra->items)
                        {
                            if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&iv))
                            {
                                if (*pobj)
                                {
                                    const Value * keyv = get_prop(**pobj, _array_merge_key);
                                    std::string key;
                                    if (keyv)
                                    {
                                        if (auto ks = std::get_if<std::string>(keyv))
                                            key = *ks;
                                        else if (auto ki = std::get_if<int64_t>(keyv))
                                            key = std::to_string(*ki);
                                    }
                                    if (!key.empty())
                                    {
                                        auto it2 = index.find(key);
                                        if (it2 != index.end())
                                        {
                                            out->items[it2->second] = iv; // 覆盖更新
                                        }
                                        else
                                        {
                                            out->items.push_back(iv);
                                            index[key] = out->items.size() - 1;
                                        }
                                    }
                                    else
                                    {
                                        out->items.push_back(iv); // 缺键：直接追加
                                    }
                                }
                                else
                                {
                                    out->items.push_back(iv);
                                }
                            }
                            else
                            {
                                out->items.push_back(iv);
                            }
                        }
                    }
                }
                it->second = std::shared_ptr<const Array>(out);
            }
            else
            {
                // 非对象，按冲突策略
                switch (_conflict_policy)
                {
                    case ConflictPolicy::Overwrite:
                        it->second = kv.second;
                        break;
                    case ConflictPolicy::Keep:
                        break;
                    case ConflictPolicy::Error:
                        _errors.push_back(
                            ConfigError{Errc::Other,
                                        std::string("merge conflict on key '") + kv.first + "'",
                                        {kv.first}});
                        break;
                }
            }
        }
    }

    return *this;
}

/**
 * @brief 解析并包含外部配置文件（YAML/JSON）
 * @param path 文件路径（相对或绝对），解析规则受 `IncludePathMode` 影响
 * @return 返回 `Builder&`，支持链式调用
 * @details
 * - 启用条件：在定义 `CFG_ENABLE_YAML` 时支持 YAML 解析；
 * - `AsProvided` 按传入路径；`RelativeToBaseDir` 或 `RelativeToCaller` 分别基于 `_include_base_dir`
 * 或调用点路径解析；
 * - 解析失败将错误记录到 `_errors`；成功内容按合并与数组策略并入。
 */
Builder &
Builder::include_file(std::string path)
{
#ifdef CFG_ENABLE_YAML
    // 解析路径模式
    auto resolve_path = [&](const std::string & p) -> std::string
    {
        if (_include_path_mode == IncludePathMode::AsProvided)
            return p;
        // RelativeToBaseDir
        if (p.size() >= 1 && (p[0] == '/' || (p.size() >= 2 && p[1] == ':')))
            return p; // 绝对路径
        if (_include_base_dir.empty())
            return p;
        if (_include_base_dir.back() == '/' || _include_base_dir.back() == '\\')
            return _include_base_dir + p;
        return _include_base_dir + "/" + p;
    };

    const std::string resolved = resolve_path(path);

    try
    {
        YAML::Node node = YAML::LoadFile(resolved);
        Value v = yaml_node_to_value(node, _normalize);

        // 根为对象则合并对象，否则兜底到 key "value"
        if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&v))
        {
            if (*pobj)
            {
                this->merge_object(**pobj);
            }
        }
        else
        {
            _root_object.props["value"] = std::move(v);
        }
    }
    catch (const YAML::BadFile &)
    {
        _errors.push_back(
            ConfigError{Errc::IncludeOpenError,
                        std::string("include_file: cannot open file '") + resolved + "'",
                        {resolved}});
    }
    catch (const YAML::ParserException & ex)
    {
        _errors.push_back(ConfigError{Errc::IncludeParseError,
                                      std::string("include_file: parse error at ") +
                                          std::to_string(ex.mark.line + 1) + ":" +
                                          std::to_string(ex.mark.column + 1) + ": " + ex.msg,
                                      {resolved}});
    }
    catch (const std::exception & ex)
    {
        _errors.push_back(ConfigError{Errc::IncludeUnexpectedError,
                                      std::string("include_file: unexpected error: ") + ex.what(),
                                      {resolved}});
    }
#else
    (void)path;
    _errors.push_back(ConfigError{Errc::IncludeUnexpectedError,
                                  "include_file requires yaml-cpp (CFG_ENABLE_YAML not enabled)",
                                  {}});
#endif
    return *this;
}

// 记录 schema id（占位）
/**
 * @brief 设置当前使用的 JSON Schema 标识
 * @param schema_id Schema 的唯一标识或标题
 * @return 返回 `Builder&`，支持链式调用
 * @details 用于标记随后加载/添加的规则所归属的 Schema，便于冻结时输出元信息。
 */
Builder &
Builder::schema(std::string schema_id)
{
    _schema_id = std::move(schema_id);
    return *this;
}

// 添加一条 schema 规则
//   将外部给定的 SchemaRule 追加到内部规则列表，以便在 freeze 阶段进行集中校验。
/**
 * @brief 添加一条 Schema 校验规则
 * @param rule 规则定义，包含路径、类型、必填与枚举等约束
 * @return 返回 `Builder&`，支持链式调用
 */
Builder &
Builder::add_schema_rule(const SchemaRule & rule)
{
    _schema_rules.push_back(rule);
    return *this;
}

// 清空 schema 规则
//   清除先前设置的所有规则，便于在不同场景下重建校验集。
/**
 * @brief 清空已添加的所有 Schema 规则
 * @return 返回 `Builder&`，支持链式调用
 */
Builder &
Builder::clear_schema_rules()
{
    _schema_rules.clear();
    return *this;
}

#ifdef CFG_ENABLE_YAML
// 从 JSON Schema 文件加载子集规则
//   加载 JSON 或 YAML 格式的 Schema 文档，支持的子集包括：
//   - type/required/properties/enum/pattern/minimum/maximum
//   将平铺展开为若干路径规则写入 _schema_rules。
/**
 * @brief 从文件加载 JSON Schema（启用 YAML 支持时）
 * @param path 文件路径
 * @return 返回 `Builder&`
 * @details 解析根对象，提取 `$id` 或 `title` 作为 Schema 标识，并展开属性为内部规则。
 */
Builder &
Builder::load_json_schema_file(std::string path)
{
    auto append_rules_from_node =
        [&](const YAML::Node & node, const std::string & base_path, auto && self) -> void
    {
        // 处理 required 列表（仅对对象）
        if (node["required"] && node["required"].IsSequence())
        {
            for (const auto & rn : node["required"])
            {
                SchemaRule r;
                r.path = base_path.empty() ? rn.as<std::string>()
                                           : base_path + "." + rn.as<std::string>();
                r.required = true;
                _schema_rules.push_back(r);
            }
        }

        // properties 展开
        if (node["properties"] && node["properties"].IsMap())
        {
            for (const auto & kv : node["properties"])
            {
                const std::string key = kv.first.as<std::string>();
                const YAML::Node & sch = kv.second;
                const std::string path_here = base_path.empty() ? key : base_path + "." + key;

                SchemaRule r;
                r.path = path_here;
                if (sch["type"])
                {
                    const std::string typ = sch["type"].as<std::string>("");
                    if (typ == "null")
                        r.expected_type = SchemaValueType::Null;
                    else if (typ == "boolean")
                        r.expected_type = SchemaValueType::Bool;
                    else if (typ == "integer")
                        r.expected_type = SchemaValueType::Int64;
                    else if (typ == "number")
                        r.expected_type = SchemaValueType::Number;
                    else if (typ == "string")
                        r.expected_type = SchemaValueType::String;
                    else if (typ == "array")
                        r.expected_type = SchemaValueType::Array;
                    else if (typ == "object")
                        r.expected_type = SchemaValueType::Object;
                }
                if (sch["minimum"])
                {
                    r.has_min = true;
                    r.min_value = sch["minimum"].as<double>();
                }
                if (sch["maximum"])
                {
                    r.has_max = true;
                    r.max_value = sch["maximum"].as<double>();
                }
                if (sch["enum"])
                {
                    if (sch["enum"].IsSequence())
                    {
                        for (const auto & ev : sch["enum"])
                        {
                            if (ev.IsNull())
                                r.enum_values.push_back(nullptr);
                            else if (ev.IsScalar())
                            {
                                // 尝试按 bool/int/double/string 顺序解析
                                try
                                {
                                    bool b = ev.as<bool>();
                                    r.enum_values.push_back(b);
                                    continue;
                                }
                                catch (...)
                                {
                                }
                                try
                                {
                                    long long ll = ev.as<long long>();
                                    r.enum_values.push_back(static_cast<int64_t>(ll));
                                    continue;
                                }
                                catch (...)
                                {
                                }
                                try
                                {
                                    double d = ev.as<double>();
                                    r.enum_values.push_back(d);
                                    continue;
                                }
                                catch (...)
                                {
                                }
                                r.enum_values.push_back(ev.as<std::string>());
                            }
                        }
                    }
                }
                if (sch["pattern"])
                {
                    r.regex_pattern = sch["pattern"].as<std::string>();
                }

                _schema_rules.push_back(r);

                // 递归子对象
                self(sch, path_here, self);
            }
        }

        // items（数组元素约束）—简化：将约束附加到 "base_path[*]"，此实现暂不展开到具体索引
        if (node["items"])
        {
            const std::string path_items =
                base_path.empty() ? std::string("[*]") : base_path + "[*]";
            SchemaRule r;
            r.path = path_items;
            const YAML::Node & sch = node["items"];
            if (sch["type"])
            {
                const std::string typ = sch["type"].as<std::string>("");
                if (typ == "null")
                    r.expected_type = SchemaValueType::Null;
                else if (typ == "boolean")
                    r.expected_type = SchemaValueType::Bool;
                else if (typ == "integer")
                    r.expected_type = SchemaValueType::Int64;
                else if (typ == "number")
                    r.expected_type = SchemaValueType::Number;
                else if (typ == "string")
                    r.expected_type = SchemaValueType::String;
                else if (typ == "array")
                    r.expected_type = SchemaValueType::Array;
                else if (typ == "object")
                    r.expected_type = SchemaValueType::Object;
            }
            if (sch["minimum"])
            {
                r.has_min = true;
                r.min_value = sch["minimum"].as<double>();
            }
            if (sch["maximum"])
            {
                r.has_max = true;
                r.max_value = sch["maximum"].as<double>();
            }
            if (sch["pattern"])
            {
                r.regex_pattern = sch["pattern"].as<std::string>();
            }
            _schema_rules.push_back(r);
        }
    };

    try
    {
        YAML::Node root = YAML::LoadFile(path);
        if (root.IsMap())
        {
            // 若包含 $id 或 title，可同步到 _schema_id
            if (root["$id"])
                _schema_id = root["$id"].as<std::string>("");
            else if (root["title"])
                _schema_id = root["title"].as<std::string>("");
            append_rules_from_node(root, "", append_rules_from_node);
        }
        else
        {
            ConfigError e{Errc::SchemaRootNotObject, "schema: root must be an object", {path}};
            e.expected_type = SchemaValueType::Object;
            _errors.push_back(std::move(e));
        }
    }
    catch (const YAML::BadFile &)
    {
        _errors.push_back(ConfigError{Errc::IncludeOpenError,
                                      std::string("schema: cannot open file '") + path + "'",
                                      {path}});
    }
    catch (const YAML::ParserException & ex)
    {
        _errors.push_back(ConfigError{
            Errc::IncludeParseError, std::string("schema: parse error: ") + ex.msg, {path}});
    }
    catch (const std::exception & ex)
    {
        _errors.push_back(ConfigError{Errc::IncludeUnexpectedError,
                                      std::string("schema: unexpected error: ") + ex.what(),
                                      {path}});
    }
    return *this;
}
#else
/**
 * @brief 加载 JSON Schema 文件的占位实现（未启用 YAML）
 * @param path 文件路径
 * @return 返回 `Builder&`
 * @details 未启用 `CFG_ENABLE_YAML` 时，不执行解析并记录错误。
 */
Builder &
Builder::load_json_schema_file(std::string path)
{
    (void)path;
    _errors.push_back(ConfigError{
        Errc::Other, "load_json_schema_file requires yaml-cpp (CFG_ENABLE_YAML not enabled)", {}});
    return *this;
}
#endif

// 辅助：根据 Value 判定 SchemaValueType
/**
 * @brief 根据值推断对应的 SchemaValueType
 * @param v 值
 * @return 若能推断则返回类型，否则返回 `std::nullopt`
 */
static SchemaValueType
infer_schema_value_type(const Value & v)
{
    if (std::holds_alternative<std::nullptr_t>(v))
        return SchemaValueType::Null;
    if (std::holds_alternative<bool>(v))
        return SchemaValueType::Bool;
    if (std::holds_alternative<int64_t>(v))
        return SchemaValueType::Int64;
    if (std::holds_alternative<double>(v))
        return SchemaValueType::Number;
    if (std::holds_alternative<std::string>(v))
        return SchemaValueType::String;
    if (std::holds_alternative<std::shared_ptr<const Array>>(v))
        return SchemaValueType::Array;
    if (std::holds_alternative<std::shared_ptr<const Object>>(v))
        return SchemaValueType::Object;
    return SchemaValueType::Object;
}

// 辅助：将路径段转换为字符串（用于错误路径输出）
/**
 * @brief 在路径向量末尾追加一个段
 * @param a 原始路径
 * @param b 追加的段
 * @return 追加后的新路径
 */
static std::vector<std::string>
join_path(const std::vector<std::string> & a, const std::string & b)
{
    auto p = a;
    p.push_back(b);
    return p;
}

// 冻结为只读对象树：若构建期存在错误则返回错误集合
/**
 * @brief 冻结当前构建数据为不可变对象树
 * @return 成功返回根对象的共享指针；失败返回错误列表
 * @details 依据合并策略与冲突策略整理最终结果，并应用已添加的 Schema 规则进行校验。
 */
expected<std::shared_ptr<const Object>, std::vector<ConfigError>>
Builder::freeze()
{
    if (!_errors.empty())
    {
        return unexpected(_errors);
    }

    // 执行 Schema 校验并集中报错
    if (!_schema_rules.empty())
    {
        std::vector<ConfigError> schema_errors;
        View root_view(std::make_shared<const Object>(_root_object));
        for (const auto & r : _schema_rules)
        {
            // 1) 必填检查
            if (r.required)
            {
                auto maybe = root_view.lookup(r.path);
                if (!maybe)
                {
                    schema_errors.push_back(
                        ConfigError{Errc::MissingKey,
                                    std::string("missing required key: ") + r.path,
                                    {r.path}});
                    continue; // 其他检查对不存在的键跳过
                }
            }

            // 查找值（若不存在且非必填，则跳过其余校验）
            auto found = root_view.lookup(r.path);
            if (!found)
            {
                continue;
            }

            const Value * cur = nullptr;
            // 提取当前节点的 Value 指针
            {
                auto ov = found->object_view();
                if (ov)
                {
                    // 对象视为对象类型
                    static Value holder_dummy; // 不使用
                }
            }
            // 直接通过内部字段访问（友元未声明，改用 entries/array_view/get_* 判断类型）

            // 2) 类型检查
            if (r.expected_type.has_value())
            {
                bool type_ok = false;
                switch (*r.expected_type)
                {
                    case SchemaValueType::Null:
                    {
                        type_ok = found->is_null();
                        break;
                    }
                    case SchemaValueType::Bool:
                        type_ok = found->get_bool().has_value();
                        break;
                    case SchemaValueType::Int64:
                    {
                        // 严格整数类型：仅当底层就是 int64 变量时才为真；
                        // 不接受 double 形式的 2.0 作为 integer。
                        auto vt = found->value_type();
                        type_ok = vt.has_value() && *vt == SchemaValueType::Int64;
                        break;
                    }
                    case SchemaValueType::Number:
                        type_ok = found->get_number().has_value();
                        break;
                    case SchemaValueType::String:
                        type_ok = found->get_string().has_value();
                        break;
                    case SchemaValueType::Array:
                        type_ok = found->array_view().has_value();
                        break;
                    case SchemaValueType::Object:
                        type_ok = found->object_view().has_value();
                        break;
                }
                if (!type_ok)
                {
                    ConfigError e{
                        Errc::TypeMismatch, std::string("type mismatch at ") + r.path, {r.path}};
                    e.expected_type = r.expected_type;
                    e.actual_type = found->value_type();
                    schema_errors.push_back(std::move(e));
                    continue;
                }
            }

            // 3) 数值范围（对 int64/number）
            if (r.has_min || r.has_max)
            {
                auto as_num = found->get_number();
                if (!as_num.has_value())
                {
                    // 尝试整数
                    auto as_int = found->get_int64();
                    if (as_int.has_value())
                        as_num = static_cast<double>(*as_int);
                }
                if (!as_num.has_value())
                {
                    ConfigError e{Errc::NumberExpected,
                                  std::string("number expected at ") + r.path,
                                  {r.path}};
                    e.expected_type = SchemaValueType::Number;
                    e.actual_type = found->value_type();
                    schema_errors.push_back(std::move(e));
                }
                else
                {
                    double d = *as_num;
                    if (r.has_min && d < r.min_value)
                    {
                        ConfigError e{Errc::OutOfRange,
                                      std::string("value < minimum at ") + r.path,
                                      {r.path}};
                        e.min_value = r.min_value;
                        schema_errors.push_back(std::move(e));
                    }
                    if (r.has_max && d > r.max_value)
                    {
                        ConfigError e{Errc::OutOfRange,
                                      std::string("value > maximum at ") + r.path,
                                      {r.path}};
                        e.max_value = r.max_value;
                        schema_errors.push_back(std::move(e));
                    }
                }
            }

            // 4) 枚举
            if (!r.enum_values.empty())
            {
                bool ok = false;
                // 严格类型匹配：先获取实际类型，再仅与同类型枚举值比较
                auto vt = found->value_type();
                if (vt.has_value())
                {
                    switch (*vt)
                    {
                        case SchemaValueType::Null:
                        {
                            for (const auto & ev : r.enum_values)
                            {
                                if (std::holds_alternative<std::nullptr_t>(ev))
                                {
                                    ok = true;
                                    break;
                                }
                            }
                            break;
                        }
                        case SchemaValueType::Bool:
                        {
                            if (auto b = found->get_bool())
                                for (const auto & ev : r.enum_values)
                                {
                                    if (std::holds_alternative<bool>(ev) &&
                                        std::get<bool>(ev) == *b)
                                    {
                                        ok = true;
                                        break;
                                    }
                                }
                            break;
                        }
                        case SchemaValueType::Int64:
                        {
                            if (auto i = found->get_int64())
                                for (const auto & ev : r.enum_values)
                                {
                                    if (std::holds_alternative<int64_t>(ev) &&
                                        std::get<int64_t>(ev) == *i)
                                    {
                                        ok = true;
                                        break;
                                    }
                                }
                            break;
                        }
                        case SchemaValueType::Number:
                        {
                            // 注意：Number 与 Int64 区分开；仅当枚举中为 double 时匹配
                            if (auto n = found->get_number())
                                for (const auto & ev : r.enum_values)
                                {
                                    if (std::holds_alternative<double>(ev) &&
                                        std::get<double>(ev) == *n)
                                    {
                                        ok = true;
                                        break;
                                    }
                                }
                            break;
                        }
                        case SchemaValueType::String:
                        {
                            if (auto s = found->get_string())
                                for (const auto & ev : r.enum_values)
                                {
                                    if (std::holds_alternative<std::string>(ev) &&
                                        std::get<std::string>(ev) == *s)
                                    {
                                        ok = true;
                                        break;
                                    }
                                }
                            break;
                        }
                        case SchemaValueType::Array:
                        case SchemaValueType::Object:
                            // 当前仅支持标量枚举；若为容器类型则直接判定为不在枚举中
                            break;
                    }
                }
                if (!ok)
                {
                    ConfigError e{Errc::EnumNotInSet,
                                  std::string("value not in enum at ") + r.path,
                                  {r.path}};
                    e.actual_type = vt;
                    schema_errors.push_back(std::move(e));
                }
            }

            // 5) 正则（仅字符串）
            if (!r.regex_pattern.empty())
            {
                auto s = found->get_string();
                if (!s.has_value())
                {
                    ConfigError e{Errc::StringExpectedForPattern,
                                  std::string("string expected for pattern at ") + r.path,
                                  {r.path}};
                    e.expected_type = SchemaValueType::String;
                    e.actual_type = found->value_type();
                    schema_errors.push_back(std::move(e));
                }
                else
                {
                    try
                    {
                        std::regex re(r.regex_pattern);
                        if (!std::regex_match(*s, re))
                        {
                            ConfigError e{Errc::RegexMismatch,
                                          std::string("regex mismatch at ") + r.path,
                                          {r.path}};
                            e.expected_pattern = r.regex_pattern;
                            schema_errors.push_back(std::move(e));
                        }
                    }
                    catch (const std::regex_error &)
                    {
                        ConfigError e{Errc::InvalidRegex,
                                      std::string("invalid regex in rule at ") + r.path,
                                      {r.path}};
                        e.expected_pattern = r.regex_pattern;
                        schema_errors.push_back(std::move(e));
                    }
                }
            }
        }

        if (!schema_errors.empty())
        {
            // 合并到 _errors 并返回
            _errors.insert(_errors.end(), schema_errors.begin(), schema_errors.end());
            return unexpected(_errors);
        }
    }

    return std::make_shared<const Object>(_root_object);
}

// 归一化键
/**
 * @brief 设置键名规范化函数（如大小写转换、去空白等）
 * @param f 键名规范化回调；为空表示使用恒等映射
 * @return 返回 `Builder&`，支持链式调用
 */
Builder &
Builder::normalize_keys(std::function<std::string(std::string_view)> f)
{
    _normalize = std::move(f);
    return *this;
}

// ---------- Builder 简易 setter 分离实现 ----------
/**
 * @brief 设置对象合并策略（浅合并或深合并）
 * @param s 合并策略
 * @return 返回 `Builder&`
 */
Builder &
Builder::set_merge_strategy(MergeStrategy s)
{
    _merge_strategy = s;
    return *this;
}

/**
 * @brief 设置冲突处理策略
 * @param p 冲突策略（优先新值或记录错误）
 * @return 返回 `Builder&`
 */
Builder &
Builder::set_conflict_policy(ConflictPolicy p)
{
    _conflict_policy = p;
    return *this;
}

/**
 * @brief 设置包含文件路径解析的基准目录
 * @param dir 基准目录
 * @return 返回 `Builder&`
 */
Builder &
Builder::set_include_base_dir(std::string dir)
{
    _include_base_dir = std::move(dir);
    return *this;
}

/**
 * @brief 设置包含文件路径解析模式
 * @param m 路径模式（按传入、相对基准目录、相对调用点）
 * @return 返回 `Builder&`
 */
Builder &
Builder::set_include_path_mode(IncludePathMode m)
{
    _include_path_mode = m;
    return *this;
}

/**
 * @brief 设置数组合并策略
 * @param s 合并策略（去重追加、覆盖等）
 * @return 返回 `Builder&`
 */
Builder &
Builder::set_array_merge_strategy(ArrayMergeStrategy s)
{
    _array_merge_strategy = s;
    return *this;
}

/**
 * @brief 设置用于对象数组去重的键名
 * @param key 对象数组项的唯一键名
 * @return 返回 `Builder&`
 */
Builder &
Builder::set_array_merge_key(std::string key)
{
    _array_merge_key = std::move(key);
    return *this;
}

} // namespace cfg